package com.linln.admin.app.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.linln.admin.app.constants.AppConstants;
import com.linln.admin.app.constants.TaskTypeEnum;
import com.linln.admin.app.domain.AppInfo;
import com.linln.admin.app.domain.AppVersion;
import com.linln.admin.app.domain.ProductionLine;
import com.linln.admin.app.domain.VersionApp;
import com.linln.admin.app.repository.InfoRepository;
import com.linln.admin.app.repository.ProductionLineRepository;
import com.linln.admin.app.repository.RepoAccountRepository;
import com.linln.admin.app.repository.VersionAppRepository;
import com.linln.admin.app.service.VersionAppService;
import com.linln.admin.app.service.VersionService;
import com.linln.admin.system.domain.TaskQueue;
import com.linln.admin.system.repository.TaskQueueRepository;
import com.linln.common.data.PageSort;
import com.linln.common.enums.StatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @author taofucheng
 * @date 2021/07/11
 */
@Slf4j
@Service
public class VersionAppServiceImpl implements VersionAppService {

    @Autowired
    private VersionAppRepository versionAppRepository;
    @Autowired
    private VersionService versionService;
    @Autowired
    private TaskQueueRepository taskQueueRepository;
    @Autowired
    private ProductionLineRepository productionLineRepository;
    @Autowired
    private InfoRepository infoRepository;
    @Autowired
    protected RepoAccountRepository accountRepository;

    /**
     * 根据ID查询数据
     *
     * @param id 主键ID
     */
    @Override
    public VersionApp getById(Long id) {
        return versionAppRepository.findById(id).orElse(null);
    }

    /**
     * 获取分页列表数据
     *
     * @param example 查询实例
     * @return 返回分页数据
     */
    @Override
    public Page<VersionApp> getPageList(Example<VersionApp> example) {
        // 创建分页对象
        PageRequest page = PageSort.pageRequest(5000);
        return versionAppRepository.findAll(example, page);
    }

    /**
     * 保存数据
     *
     * @param versionApp 实体对象
     */
    @Override
    public VersionApp save(VersionApp versionApp) {
        return versionAppRepository.save(versionApp);
    }

    /**
     * 状态(启用，冻结，删除)/批量状态处理
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateStatus(StatusEnum statusEnum, List<Long> idList) {
        return versionAppRepository.updateStatus(statusEnum.getCode(), idList) > 0;
    }

    @Override
    @Transactional
    public Long saveRelatedApps(String versionId, String[] appIds) throws JsonProcessingException {
        if (StringUtils.isBlank(versionId)) {
            throw new IllegalArgumentException("参数不正确！");
        }
        List<Long> selectedAppIds = new ArrayList<>();//页面选择的
        if (appIds != null) {
            for (String id : appIds) {
                if (StringUtils.isBlank(id)) {
                    continue;
                }
                selectedAppIds.add(Long.parseLong(id.trim()));
            }
        }

        Long vid = Long.parseLong(versionId);
        AppVersion ver = versionService.getById(vid);
        if (ver == null) {
            return null;
        }
        VersionApp va = new VersionApp();
        va.setVersion_id(vid);
        List<VersionApp> vas = versionAppRepository.findAll(Example.of(va));
        List<Long> deleted = new ArrayList<>();
        if (vas != null) {// 一个个地修改或删除
            List<Long> modified = new ArrayList<>();
            for (VersionApp tmp : vas) {
                if (selectedAppIds.contains(tmp.getApp_id())) {
                    // 存在，就表示没动过
                    modified.add(tmp.getApp_id());
                } else {
                    // 不存在，就是删除操作
                    versionAppRepository.delete(tmp);
                    deleted.add(tmp.getApp_id());
                }
            }
            //去掉没动的，剩下的就是添加的
            selectedAppIds.removeAll(modified);
        }
        saveToDb(selectedAppIds, vid);
        //新建一个创建或删除开发分支的任务
        TaskQueue tq = new TaskQueue();
        tq.setRelate_id(vid);
        tq.setType(TaskTypeEnum.CREATE_DEV_BRANCH.getType());
        tq.setStatus(AppConstants.TASK_STATUS_NEW);
        tq.setCreate_date(new Date());
        tq.setData(new ObjectMapper().writeValueAsString(deleted));//将删除的记录下来，由任务去删除分支
        taskQueueRepository.save(tq);

        if (selectedAppIds.size() > 0 && AppConstants.YES.equals(ver.getCo_release_branch())) {
            tq = new TaskQueue();
            tq.setRelate_id(vid);
            tq.setType(TaskTypeEnum.CREATE_RELEASE_BRANCH.getType());
            tq.setStatus(AppConstants.TASK_STATUS_NEW);
            tq.setCreate_date(new Date());
            taskQueueRepository.save(tq);
        }
        return tq.getId();
    }

    /**
     * 将指定的项目的dev分支代码合并到release分支
     *
     * @param versionId 版本id
     * @param recIds    项目关联表id
     * @return 创建的任务id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long mergeDev2ReleaseBranch(String versionId, String[] recIds) throws JsonProcessingException {
        if (StringUtils.isBlank(versionId) || recIds == null || recIds.length < 1) {
            throw new IllegalArgumentException("参数不正确！");
        }
        Long vid = Long.parseLong(versionId.trim());
        //判断这个版本有没有切出release分支
        AppVersion ver = versionService.getById(vid);
        if (ver == null) {
            throw new IllegalArgumentException("版本信息不存在！");
        }
        if (AppConstants.YES.equals(ver.getHotfix_flag())) {
            throw new IllegalArgumentException("修复版本不需要合并到release！");
        }
        if (AppConstants.NO.equals(ver.getCo_release_branch())) {
            throw new IllegalArgumentException("版本还没有创建release分支！");
        }
        TaskQueue tq = new TaskQueue();
        tq.setRelate_id(vid);
        tq.setType(TaskTypeEnum.MERGE_DEV_RELEASE.getType());
        tq.setStatus(AppConstants.TASK_STATUS_NEW);
        tq.setData(new ObjectMapper().writeValueAsString(recIds));
        tq.setCreate_date(new Date());
        taskQueueRepository.save(tq);
        return tq.getId();
    }

    /**
     * 将指定的项目的dev分支代码合并到release分支
     *
     * @param versionId 版本id
     * @param recIds    项目关联表id
     * @return 创建的任务id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long mergeProd2DevBranch(String versionId, String[] recIds) throws JsonProcessingException {
        if (StringUtils.isBlank(versionId) || recIds == null || recIds.length < 1) {
            throw new IllegalArgumentException("参数不正确！");
        }
        Long vid = Long.parseLong(versionId.trim());
        //判断这个版本有没有切出release分支
        AppVersion ver = versionService.getById(vid);
        if (ver == null) {
            throw new IllegalArgumentException("版本信息不存在！");
        }

        TaskQueue tq = new TaskQueue();
        tq.setRelate_id(vid);
        tq.setType(TaskTypeEnum.MERGE_PROD_DEV.getType());
        tq.setStatus(AppConstants.TASK_STATUS_NEW);
        tq.setData(new ObjectMapper().writeValueAsString(recIds));
        tq.setCreate_date(new Date());
        taskQueueRepository.save(tq);
        if (AppConstants.YES.equals(ver.getCo_release_branch())) {//存在release分支，还要将dev合并到release
            tq = new TaskQueue();
            tq.setRelate_id(vid);
            tq.setType(TaskTypeEnum.MERGE_DEV_RELEASE.getType());
            tq.setStatus(AppConstants.TASK_STATUS_NEW);
            tq.setData(new ObjectMapper().writeValueAsString(recIds));
            tq.setCreate_date(new Date());
            taskQueueRepository.save(tq);
        }
        return tq.getId();
    }

    /**
     * 将状态置为已解决冲突，同时，如果是已切出release，还要将解决完的dev分支合并到release上
     *
     * @param versionId 版本id
     * @param recIds    项目关联表id
     * @return 创建的任务id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long manualMergeBranch(String versionId, String[] recIds) throws JsonProcessingException {
        if (StringUtils.isBlank(versionId) || recIds == null || recIds.length < 1) {
            throw new IllegalArgumentException("参数不正确！");
        }
        List<Long> selectedRecIds = new ArrayList<>();
        for (String recId : recIds) {
            selectedRecIds.add(Long.parseLong(recId));
        }
        Long vid = Long.parseLong(versionId.trim());
        VersionApp va = new VersionApp();
        va.setVersion_id(vid);
        List<VersionApp> vas = versionAppRepository.findAll(Example.of(va));
        if (vas == null || vas.isEmpty()) {
            throw new IllegalArgumentException("没有关联的项目信息");
        }
        AppVersion ver = versionService.getById(vid);
        for (VersionApp v : vas) {
            if (!selectedRecIds.contains(v.getId())) {
                continue;//如果不是选中的，就不需要进行操作。
            }
            if (AppConstants.VERSION_MERGE_STATUS_CONFLICT.equals(v.getMerge_from_status())) {
                v.setMerge_from_status(AppConstants.VERSION_MERGE_STATUS_MANUAL_MERGED);
                v.setMerge_from_time(new Date());
                //判断这个版本有没有切出release分支
                if (AppConstants.YES.equals(ver.getCo_release_branch())) {
                    TaskQueue tq = new TaskQueue();
                    tq.setRelate_id(vid);
                    tq.setType(TaskTypeEnum.MERGE_DEV_RELEASE.getType());
                    tq.setStatus(AppConstants.TASK_STATUS_NEW);
                    tq.setData(new ObjectMapper().writeValueAsString(new Long[]{v.getApp_id()}));
                    tq.setCreate_date(new Date());
                    taskQueueRepository.save(tq);
                }
            }
            if (AppConstants.VERSION_MERGE_STATUS_CONFLICT.equals(v.getMerge_to_status())) {
                v.setMerge_to_status(AppConstants.VERSION_MERGE_STATUS_MANUAL_MERGED);
                v.setMerge_to_time(new Date());
                //判断这个版本是不是已经上线，上线的还要将prod合并到所有dev分支
                if (AppConstants.YES.equals(ver.getPublished())) {
                    TaskQueue tq = new TaskQueue();
                    tq.setRelate_id(vid);
                    tq.setType(TaskTypeEnum.PUBLISHED.getType());
                    tq.setStatus(AppConstants.TASK_STATUS_NEW);
                    tq.setData(new ObjectMapper().writeValueAsString(new Long[]{v.getApp_id()}));
                    tq.setCreate_date(new Date());
                    taskQueueRepository.save(tq);
                }
            }
            versionAppRepository.save(v);
        }

        return null;
    }

    @Override
    public String getProductionTitle(Long appId) {
        Optional<AppInfo> app = infoRepository.findById(appId);
        if (!app.isPresent()) {
            return "";
        }
        Optional<ProductionLine> prod = productionLineRepository.findById(app.get().getProd_line_id());
        if (!prod.isPresent()) {
            return "";
        }
        return prod.get().getTitle();
    }

    /**
     * 进行mvn的deploy打包
     *
     * @param versionId 所属版本
     * @param recIds    选中的应用id
     * @return 返回红打包结果
     */
    @Override
    public Long deploy(String versionId, String[] recIds) throws JsonProcessingException {
        if (StringUtils.isBlank(versionId) || recIds == null || recIds.length < 1) {
            throw new IllegalArgumentException("参数不正确！");
        }
        TaskQueue tq = new TaskQueue();
        tq.setRelate_id(Long.valueOf(versionId));
        tq.setType(TaskTypeEnum.MVN_DEPLOY.getType());
        tq.setStatus(AppConstants.TASK_STATUS_NEW);
        tq.setData(new ObjectMapper().writeValueAsString(recIds));
        tq.setCreate_date(new Date());
        taskQueueRepository.save(tq);
        return tq.getId();
    }


    /**
     * 将新增的保存进数据库，并准备切出新分支
     *
     * @param newAppIds
     * @param vid
     */
    private void saveToDb(List<Long> newAppIds, Long vid) {
        List<VersionApp> es = new ArrayList<>();
        for (Long appId : newAppIds) {
            VersionApp tmp = new VersionApp();
            tmp.setVersion_id(vid);
            tmp.setApp_id(appId);
            tmp.setAdd_time(new Date());
            tmp.setHas_dev(AppConstants.NO);
            es.add(tmp);
        }
        if (es.size() > 0) {
            versionAppRepository.saveAll(es);
        }
    }
}